""" Cython-based Python Module for Python 3 """
from buildutils import *
import Cython.Build

Import('env', 'build', 'install')

localenv = env.Clone()


def configure_python(env, python_command):
    script = '\n'.join(("from distutils.sysconfig import *",
                        "import numpy",
                        "print(get_config_var('EXT_SUFFIX') or get_config_var('SO'))",
                        "print(get_config_var('INCLUDEPY'))",
                        "print(get_config_var('LDLIBRARY'))",
                        "print(get_config_var('prefix'))",
                        "print(get_python_version())",
                        "print(numpy.get_include())"))
    info = getCommandOutput(python_command, '-c', script)
    module_ext, inc, pylib, prefix, py_version, numpy_include = info.splitlines()[-6:]
    env.Prepend(CPPPATH=[Dir('#include'), inc, numpy_include])
    env.Prepend(LIBS=env['cantera_libs'])
    if env['OS'] == 'Darwin':
        env.Append(LINKFLAGS='-undefined dynamic_lookup')
    elif env['OS'] == 'Windows':
        env.Append(LIBPATH=prefix+'/libs')
        if env['toolchain'] == 'mingw':
            env.Append(LIBS='python%s' % py_version.replace('.',''))
            if env['OS_BITS'] == 64:
                env.Append(CPPDEFINES='MS_WIN64')
            # fix for http://bugs.python.org/issue11566
            env.Append(CPPDEFINES={'_hypot':'hypot'})
    elif env['OS'] == 'Cygwin':
        # extract 'pythonX.Y' from 'libpythonX.Y.dll.a'
        env.Append(LIBS=pylib[3:-6])
    return module_ext, py_version


def add_dependencies(mod, ext):
    localenv.Depends(mod, ext)
    localenv.Depends(mod, dataFiles + testFiles)
    localenv.Depends(ext, localenv['cantera_staticlib'])

    for f in (mglob(localenv, 'cantera', 'py') +
              mglob(localenv, 'cantera/test', 'py') +
              mglob(localenv, 'cantera/mixmaster', 'py') +
              mglob(localenv, 'cantera/mixmaster/Units', 'py') +
              mglob(localenv, 'cantera/examples/tutorial', 'py') +
              mglob(localenv, 'cantera/examples/equilibrium', 'py') +
              mglob(localenv, 'cantera/examples/kinetics', 'py') +
              mglob(localenv, 'cantera/examples/transport', 'py') +
              mglob(localenv, 'cantera/examples/reactors', 'py') +
              mglob(localenv, 'cantera/examples/onedim', 'py') +
              mglob(localenv, 'cantera/examples/surface_chemistry', 'py') +
              mglob(localenv, 'cantera/examples/misc', 'py')):
        localenv.Depends(mod, f)


def cythonize(target, source, env):
    Cython.Build.cythonize([f.abspath for f in source])

cythonized = localenv.Command('cantera/_cantera.cpp', ['cantera/_cantera.pyx'],
                              cythonize)
for f in mglob(localenv, 'cantera', 'pyx', 'pxd'):
    localenv.Depends(cythonized, f)

for line in open('cantera/_cantera.pxd'):
    m = re.search(r'from "(cantera.*?)"', line)
    if m:
        localenv.Depends('cantera/_cantera.cpp', '#include/' + m.group(1))

def install_module(prefix, python_version):
    major = python_version[0]
    minor = python_version.split('.')[1]
    ver = '3' if major == '3' else ''
    dummy = 'dummy' + major
    if prefix == 'USER':
        # Install to the OS-dependent user site-packages directory
        extra = '--user'
        if localenv['OS'] == 'Darwin':
            extra += ' --prefix=""'
    elif prefix:
        # A specific location for the Cantera python module has been given
        if localenv['debian'] and localenv.subst(prefix) == '/usr/local':
            # Installation to /usr/local is the default on Debian-based distributions
            extra = ''
        elif localenv['OS'] == 'Darwin':
            extra = localenv.subst(' --prefix=${python%s_prefix}' % ver)
        elif localenv['libdirname'] == 'lib64':
            # 64-bit RHEL / Fedora
            extra = localenv.subst(
                ' --prefix=${python%s_prefix} --install-lib=${python%s_prefix}/lib64/python%s.%s/site-packages' % (ver, ver, major, minor))
        else:
            extra = '--user'
            localenv.AppendENVPath(
                'PYTHONUSERBASE',
                normpath(localenv.subst('$python%s_prefix' % ver)))
    else:
        # Install Python module in the default location
        extra = ''

    if localenv['PYTHON_INSTALLER'] == 'direct':
        mod_inst = install(localenv.Command, dummy, mod,
                           build_cmd + ' install %s' % extra +
                           ' --record=../../build/python%s-installed-files.txt' % major +
                           ' --single-version-externally-managed')
        global_env = env
        def find_module_dir(target, source, env):
            check = pjoin('cantera','__init__.py')
            for filename in open('build/python%s-installed-files.txt' % major).readlines():
                filename = filename.strip()
                if filename.endswith(check):
                    filename = filename.replace(check,'')
                    global_env['python%s_module_loc' % ver] = normpath(filename)
                    break
        localenv.AlwaysBuild(localenv.AddPostAction(mod_inst, find_module_dir))
        if not ver:
          env['install_python2_action'] = mod_inst

    elif localenv['PYTHON_INSTALLER'] == 'debian':
        install(localenv.Command, dummy, mod,
                build_cmd + ' install --install-layout=deb --no-compile %s' % extra)
        env['python%s_module_loc' % ver] = '<unspecified>'
    elif localenv['PYTHON_INSTALLER'] == 'binary':
        install(localenv.Command, dummy, mod,
                build_cmd + ' bdist_msi --dist-dir=../..' +
                ' --target-version=%s' % python_version)
        env['python%s_module_loc' % ver] = '<unspecified>'

dataFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/data',
                                      '#build/data')
build(dataFiles)

testFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/test/data',
                                      '#test/data')
build(testFiles)

# Cython module for Python 3.x
if localenv['python3_package'] == 'y':
    py3env = localenv.Clone()
    module_ext, py3_version = configure_python(py3env, py3env['python3_cmd'])

    obj = py3env.SharedObject('#build/temp-py/_cantera3', 'cantera/_cantera.cpp')
    ext = py3env.LoadableModule('#build/python3/cantera/_cantera%s' % module_ext,
                                obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
                                SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
    py3env['py_extension'] = ext[0].name

    py3env.SubstFile('setup3.py', 'setup.py.in')
    build_cmd = ('cd interfaces/cython &&'
                 ' $python3_cmd setup3.py build --build-lib=../../build/python3')
    mod = build(py3env.Command('#build/python3/cantera/__init__.py', 'setup3.py',
                               build_cmd))
    env['python3_module'] = mod
    env['python3_extension'] = ext

    add_dependencies(mod, ext)
    install_module(py3env['python3_prefix'], py3_version)


# Cython module for Python 2.x
if localenv['python_package'] == 'full':
    py2env = localenv.Clone()
    module_ext, py2_version = configure_python(py2env, py2env['python_cmd'])

    obj = py2env.SharedObject('#build/temp-py/_cantera2', 'cantera/_cantera.cpp')
    ext = py2env.LoadableModule('#build/python2/cantera/_cantera%s' % module_ext,
                                obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
                                SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
    py2env['py_extension'] = ext[0].name
    py2env.SubstFile('setup2.py', 'setup.py.in')
    build_cmd = ('cd interfaces/cython &&'
                 ' $python_cmd_esc setup2.py build --build-lib=../../build/python2')
    mod = build(py2env.Command('#build/python2/cantera/__init__.py',
                               'setup2.py',
                               build_cmd))
    env['python2_module'] = mod
    env['python2_extension'] = ext

    # Use 3to2 to convert examples from Python 3 syntax
    if env['python_convert_examples']:
        def convert_example(target, source, env):
            shutil.copyfile(source[0].abspath, target[0].abspath)
            if env['OS'] == 'Windows':
                python_dir = os.path.dirname(which(env['python_cmd']))
                threetotwo_cmd = pjoin(python_dir, 'Scripts', '3to2')
                subprocess.call([env['python_cmd'], threetotwo_cmd, '--no-diff', '-n', '-w','-x', 'str',
                             '-f', 'all', '-f', 'printfunction', '-x', 'print',
                             '-x', 'open', target[0].abspath])
            else:
                subprocess.call(['3to2', '--no-diff', '-n', '-w','-x', 'str',
                             '-f', 'all', '-f', 'printfunction', '-x', 'print',
                             '-x', 'open', target[0].abspath])

        for subdir in subdirs('cantera/examples'):
            dirpath = pjoin('cantera', 'examples', subdir)
            for filename in os.listdir(dirpath):
                if not filename.endswith('.py'):
                    continue
                targetdir = '../../build/python2/cantera/examples'
                a = build(py2env.Command(pjoin(targetdir, subdir, filename),
                                         pjoin(dirpath, filename),
                                         convert_example))
                py2env.Depends(a, mod)

    add_dependencies(mod, ext)
    install_module(py2env['python_prefix'], py2_version)
